package com.fjwt.gz.service.activity.game;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjwt.gz.core.constants.Constants;
import com.fjwt.gz.db.bo.ActivityAwardAndSettingBo;
import com.fjwt.gz.db.bo.ActivityAwardBO;
import com.fjwt.gz.db.entity.ActivityAwardEntity;
import com.fjwt.gz.service.impl.ActivityAwardService;
import com.fjwt.gz.service.mapper.ActivityAwardMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;

/**
 * 抽奖工具类  service
 * @Author: Will
 * @Date: 2024-11-02
 * @Version: 1.0
 */
@Slf4j
@Service
public class DrawUtilService extends ServiceImpl<ActivityAwardMapper, ActivityAwardEntity> {

    @Autowired
    private ActivityAwardService activityAwardService;

    /**
     * 中奖最大权重(按总计100%权重计算)---前端最小中奖概率0.01%（传给后端 *100）
     */
    private final int WEIGHT = 10000;

    /**
     * 中奖概率类型： 0按比例中奖 ，1顺延中奖，2百分百中奖
     */
    private final int AWARD_NEXT = 1;

    /**
     * 中奖概率类型： 0按比例中奖 ，1顺延中奖，2百分百中奖
     */
    private final int AWARD_OK = 2;

    /**
     * 进行抽奖
     *
     * @param awardType         抽奖类型
     * @param activityAwardList 奖品列表
     * @return 返回奖品对象
     */
    public ActivityAwardBO draw(int awardType, List<ActivityAwardAndSettingBo> activityAwardList) {
        List<ActivityAwardBO> activityAwardBOList = activityAwardService.getAwardList(activityAwardList);
//        是否包含安慰奖
        List<ActivityAwardBO> consolationAwardBOList = new ArrayList<>();
        Iterator<ActivityAwardBO> iterator = activityAwardBOList.iterator();
        while (iterator.hasNext()) {
            ActivityAwardBO awardBO = iterator.next();
            if (awardBO.getAwardType() == Constants.AWARD.SCORE && awardBO.getAwardNum() == 0) {
                consolationAwardBOList.add(awardBO);
                iterator.remove();
            }
        }
        log.info("筛选出来的安慰奖列表：{}", JSONUtil.toJsonStr(consolationAwardBOList));
        log.info("过滤后的奖品列表：{}", JSONUtil.toJsonStr(activityAwardBOList));
// 进行抽奖
        Integer index = toDraw(awardType, activityAwardBOList);
        log.info("用户抽到过滤后的奖品列表index：{}", index);
        if (index != null) {
            ActivityAwardBO activityAwardBO = activityAwardBOList.get(index);
            if ( activityAwardService.reduceNum(activityAwardBO.getAwardId(),activityAwardBO.getAwardType())!= null) {
              return activityAwardBO;
            }
            if (AWARD_NEXT == awardType) {
                log.info("进入顺延中奖模式");
                for (int i = index + 1; i < activityAwardBOList.size(); i++) {
                    if ( activityAwardService.reduceNum(activityAwardBO.getAwardId(),activityAwardBO.getAwardType())!= null) {
                        return  activityAwardBOList.get(i);
                    }
                }
            }
        }
        //所有空奖都转化为安慰奖
        int size = consolationAwardBOList.size();
        if (size != 0) {
            SecureRandom secureRandom = new SecureRandom();
            int randomInt = secureRandom.nextInt(size);
            log.info("用户抽到筛选出来的安慰奖列表index：{}", randomInt);
            ActivityAwardBO activityAwardBO = consolationAwardBOList.get(randomInt);
            if ( activityAwardService.reduceNum(activityAwardBO.getAwardId(),activityAwardBO.getAwardType())!= null) {
                return activityAwardBO;
            }
        }
        return null;
    }

    /**
     * 白名单进行抽奖
     *
     * @param awardLevel        奖品级别
     * @param activityAwardList 奖品列表
     * @return 返回奖品对象
     */
    public ActivityAwardBO drawByWhiteList(int awardLevel, List<ActivityAwardEntity> activityAwardList) {
        Integer index = null;
        for (int i = 0; i < activityAwardList.size(); i++) {
            if (awardLevel == activityAwardList.get(i).getAwardLevel()) {
                index = i;
                break;
            } else {
                continue;
            }
        }
        if (index != null) {
            ActivityAwardEntity activityAwardEntity = activityAwardList.get(index);
            ActivityAwardBO activityAwardBO = new ActivityAwardBO();
            activityAwardBO.setAwardId(activityAwardEntity.getAwardId());
            activityAwardBO.setAwardType(activityAwardEntity.getAwardType());
            boolean isReduceSuccess =  activityAwardService.reduceNum(activityAwardBO.getAwardId(),activityAwardBO.getAwardType())!= null;
            if (isReduceSuccess) {
                return activityAwardBO;
            } else {
                log.info(String.format("白名单用户因库存不足，没有中奖"));
            }
        } else {
            log.info(String.format("白名单用户因奖品级别配置错误，没有中奖"));
        }
        return null;
    }

    /**
     * 随机抽取奖品
     *
     * @return 返回奖品列表下标
     */
    private Integer toDraw(int awardType, List<ActivityAwardBO> activityAwardBOList) {
//        按中奖概率权重进行排序
        if (AWARD_OK == awardType) {
            log.info("进入百分之百中奖模式");
            for (ActivityAwardBO activityAwardBO : activityAwardBOList) {
                activityAwardBO.setActualNum(activityAwardBO.getAwardNum() - activityAwardBO.getAwardGet());
            }
            activityAwardBOList.sort(Comparator.comparingInt(ActivityAwardBO::getActualNum));
        } else {
            log.info("进入概率中奖模式");
            activityAwardBOList.sort(Comparator.comparingInt(ActivityAwardBO::getAwardProbability));
        }

//        按权重生成计算节点
        List<Integer> nodeList = new ArrayList<>();
        nodeList.add(0);
        for (ActivityAwardBO activityAwardBO : activityAwardBOList) {
            nodeList.add(nodeList.get(nodeList.size() - 1) + activityAwardBO.getAwardProbability());
        }
        int maxInt = nodeList.get(nodeList.size() - 1);
        if (AWARD_OK != awardType && maxInt < WEIGHT) {
            maxInt = WEIGHT;
        }
        log.info(String.format("本次活动最大权重值为：%s", maxInt));

//      生成随机数
        SecureRandom secureRandom = new SecureRandom();
        int randomInt = secureRandom.nextInt(maxInt);
        log.info(String.format("用户在本次活动产生的随机数为:%s", randomInt));
//      进行抽奖
        for (int i = 1; i < nodeList.size(); i++) {
            int endNode = nodeList.get(i);
            int startNode = nodeList.get(i - 1);
            if (randomInt >= startNode && randomInt < endNode) {
                return i - 1;
            }
        }
        return null;
    }

}
